/* 
     * File:   ciciSoundSource.h
 * Author: manu
 * Source of sound.
 * Waiting for data and emit the buffer
 * use openAL
 * Created on 25 avril 2010, 21:06
 */

#ifndef _CICISOUNDSOURCE_H
#define	_CICISOUNDSOURCE_H



#endif	/* _CICISOUNDSOURCE_H */


#include <stdlib.h>
//from package libopenal-dev
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alext.h>
//from package libalut-dev
#include <AL/alut.h>

#define CICISOUNDSOURCE_BUFFER_SIZE (4096 * 8)
#define CICISOUNDSOURCE_FREQUENCY 44100

/** unsigned 32-bit integer */
typedef unsigned int ciciType32b ;
/** unsigned 16-bit integer */
typedef unsigned short int ciciType16b ;

class ciciSoundSource
{
public:
    bool update(const unsigned int *size ,const ciciType16b *data) ; //Update the stream if necessary
    bool feedToBuffer(unsigned int *size ,ciciType16b *data ,ALuint *buffer);
private :
    ALuint buffers[2]; // front and back buffers
    ALuint cfBuffer  ;    //currentFeededBuffer
    ALuint sizeFeedingCfBuffer = 0 ;
    ALuint source;     // audio source
    ALenum format;     // internal format
    unsigned int nbWaitingBytes ; //to trigger the buffer at right time
protected:
    void check();  // checks OpenAL error state
    bool stream(ALuint buffer);   // reloads a buffer
};


ciciSoundSource::feedToBuffer(unsigned int *size , ciciType16b *data )
{
    int processed = 0 ;

    if( !cfBuffer ) //si pas de buffer en cours de remplissage
    {
        alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
        if( processed == 0)
        {
            malloc()
        } 
        
        alSourceUnqueueBuffers(source, 1, &cfBuffer); //on récupere un buffer pas utilisé
        check();
    
    
    if(( sizeFeedingCfBuffer + size) < CICISOUNDSOURCE_BUFFER_SIZE )
    {
        alBufferData(cfBuffer,AL_FORMAT_MONO16, data, size, CICISOUNDSOURCE_FREQUENCY);
        sizeFeedingCfBuffer += *size ;
        size = 0 ;
    }
    if((sizeFeedingCfBuffer + size) >= CICISOUNDSOURCE_BUFFER_SIZE)
    {
        alBufferData(cfBuffer,AL_FORMAT_MONO16, data, CICISOUNDSOURCE_BUFFER_SIZE-sizeFeedingCfBuffer, CICISOUNDSOURCE_FREQUENCY);
        *size = *size - CICISOUNDSOURCE_BUFFER_SIZE - sizeFeedingCfBuffer ;
        data = data + CICISOUNDSOURCE_BUFFER_SIZE - sizeFeedingCfBuffer ;
        sizeFeedingCfBuffer = 0  ;
        alSourceQueueBuffers(source, 1, &cfBuffer); //on le refout de l'autre coté
        check();
        cfBuffer = void ;
    }
    if ( size > 0) //Tant que le flux entrant n'est pas écoulé
    {
        feedToBuffer(size,data);
    }
    return true ;
}


ciciSoundSource::update(const unsigned int size ,const ciciType16b *data)
{
    const unsigned int vSize = size ;
    const ciciType16b *vData = data ;
    //on répupere le nombre de buffers pas utilisés
    memcpy(vData,data,size);

    feedToBuffer(&vSize ,vData); //on le remplit

}


void ciciSoundSource::check()
{
    int error = alGetError();

    if(error != AL_NO_ERROR)
        throw std::string("OpenAL error was raised.");
}